<!--
 * @Description: 观察者模式
 * @Author: 小费
 * @Date: 2021-03-10 21:50:25
 * @LastEditTime: 2021-03-11 22:33:44
 * @LastEditors: 小费
 * @Reference:
-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>观察者模式</title>
    <style type="text/css">
        .container {
            width: 70%;
            min-width: 900px;
            margin: 0 auto;
            font-size: 20px;
            color: #666;
            line-height: 30px;
        }

        code {
            display: block;
            background-color: #eee;
            padding: 10px;
            line-height: 30px;
        }
    </style>
    <script type="module" src="./observer/observer.js"></script>
</head>

<body>
    <div class="container">
        <h2>1 观察者模式:</h2>
        <p>
            以学生为例，上课和下课的铃声就是被观察者，学生就是观察者，当下课铃声响了，学生就知道下课了，就出去跑着玩了，
            然后过了10分钟，上课铃声又响了，然后学生听到上课铃，又开始从外面往教室跑，去上课。
        </p>
        <p>
            其实我们在平时也用到过观察者模式，只是我们没有注意到而已，举一个简单的例子：
            我们曾经在DOM节点上面绑定过事件函数，那我们就使用过观察者模式，因为JS和DOM之间就是实现了一种观察者模式。
        </p>
        <code>
            document.body.addEventListener("click", function () {
            console.log("Hello World")
            },false)

            document.body.click() //模拟用户点击
        </code>

        <div><dfn>2观察者模式优缺点</dfn></div>

        <p><strong>优势：</strong>目标者与观察者，功能耦合度降低，专注自身功能逻辑；观察者被动接收更新，时间上解耦，实时接收目标者更新状态。</p>
        <p><strong>缺点：</strong>观察者模式虽然实现了对象间依赖关系的低耦合，但却不能对事件通知进行细分管控，如 “筛选通知”，“指定主题事件通知”</p>
        <p>比如上面的例子，仅通知 “前端开发者” ？观察者对象如何只接受自己需要的更新通知？上例中，两个观察者接收目标者状态变更通知后，都执行了 update()，并无区分。
            “00后都在追求个性的时代，我能不能有点不一样？”，这就引出我们的下一个模式。进阶版的观察者模式。
        </p>
        <div class="image">
            <img src="./image/observer-1.png" alt=""/>
        </div>
    </div>
    <script type="text/javascript">
        /**console.log
         * 目标对象
         * @description:
         * @param  {*}
         * @return {*}
         */
        function Subject() {
            // const observers = []
        }
        Subject.prototype = {
            Constructor: Subject,
            observers: [],
            add: function (observer) {
                this.observers.push(observer)
            },
            update: function (value, index) {
                this.observers[index] = value
            },
            delete: function (index) {
                this.observers.splice(index, 1)
            },
            notify: function () {
                console.log(this.observers)
                for (let i = 0, len = this.observers.length; i < len; i++) {
                    this.observers[i].update()
                }
            }
        }


        /**
         * 观察者对象
         * @description:
         * @param  {*}
         * @return {*}
         * @param {*} options
         */
        function Observer(options) {
            this.$options = typeof options === "object" ? options : {}
            this.name = options.name
        }

        Observer.prototype = {
            Constructor: Observer,
            /*** 目标更新世时被触发*/
            update: function () {
                console.log("目标通知观察者更新,观察者:", this.name)
            }
        }
        // 实例化两个观察者
        const obs1 = new Observer({
            name: "小李"
        })
        const obs2 = new Observer({
            name: "小李飞刀"
        })
        //实例化一个目标者(被观察者)
        const subject = new Subject()
        subject.add(obs1)
        subject.add(obs2)
        //目标者发出通知
        subject.notify()
    </script>
</body>

</html>
